package com.sduept.nwld.kpi.controller;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import javax.inject.Named;
import javax.faces.view.ViewScoped;

import org.primefaces.model.DefaultTreeNode;
import org.primefaces.model.TreeNode;

import com.sduept.core.dao.SuperDAO;
import com.sduept.bigdata.web.jsf.controller.AbstractController;
import com.sduept.nwld.dataserver.util.LibTreeNode;
import com.sduept.nwld.kpi.datasource.KpiDataSource;
import com.sduept.nwld.kpi.manager.KpiManager;
import com.sduept.nwld.kpi.model.KpiGroup;
import com.sduept.nwld.kpi.model.KpiLevel;
import com.sduept.nwld.kpi.model.KpiNormal;
import com.sduept.nwld.kpi.model.KpiWeight;

@Named
@ViewScoped
public class KpiGroupViewController extends AbstractController{

	/**
	 * 
	 */
	private static final long serialVersionUID = 7019723441806294669L;

	@Autowired
	private KpiManager km;
	@Autowired
	private SuperDAO dao;
	
	private TreeNode root;
	private TreeNode selectedNode;
	
	private KpiNormal currentKpi;
	private KpiDataSource currentDataSource;
	private boolean realiIsShow = true;

	private Map<String,KpiGroup> groupsmap = new HashMap<>();
	private Map<String,KpiLevel> levelsmap = new HashMap<>();
	private Map<String,KpiNormal> kpismap = new HashMap<>();
	private Map<String,KpiDataSource> dsmap = new HashMap<>();
	private List<KpiLevel> levels = new ArrayList<>();

	private Map<String,List<KpiNormal>> groupKpiMap = new HashMap<>();
	private Map<String,List<KpiGroup>> groupGroupMap = new HashMap<>();
	private Map<String,List<KpiWeight>> kpiWeightsMap = new HashMap<>();
	
	@PostConstruct
	public void init(){
		List<KpiGroup> groups = dao.findAll(KpiGroup.class);
		List<KpiNormal> kpis = dao.findAll(KpiNormal.class);
		List<KpiWeight> weights = dao.findAll(KpiWeight.class);
		List<KpiDataSource> sources = dao.findAll(KpiDataSource.class);
		levels = km.findLevelsAllOrderByValue();
		
		groupGroupMap.clear();
		for(KpiGroup g:groups){
			groupsmap.put(g.getId(), g);
			String pid = g.getPid() == null? "root":g.getPid();
			List<KpiGroup> tmps = groupGroupMap.get(pid);
			if(tmps == null){
				tmps = new ArrayList<>();
				groupGroupMap.put(pid, tmps);
			}
			tmps.add(g);
		}
		
		groupKpiMap.clear();
		kpismap.clear();
		for(KpiNormal n:kpis){
			kpismap.put(n.getId(), n);
			String groupid = n.getKpiGroup();
			List<KpiNormal> tmps = groupKpiMap.get(groupid);
			if(tmps == null){
				tmps = new ArrayList<>();
				groupKpiMap.put(groupid, tmps);
			}
			tmps.add(n);
		}
		levelsmap.clear();
		for(KpiLevel l:levels){
			levelsmap.put(l.getId(), l);
		}
		dsmap.clear();
		for(KpiDataSource ds:sources){
			dsmap.put(ds.getId(), ds);
		}
		kpiWeightsMap.clear();
		for (KpiWeight w : weights) {
			List<KpiWeight> ws = kpiWeightsMap.get(w.getPid());
			if(ws == null){
				ws = new ArrayList<>();
				kpiWeightsMap.put(w.getPid(), ws);
			}
			ws.add(w);
		}
		
		root = new LibTreeNode("root","指标", null);
		loadChildren(root,"group");
	}
	public void onKpiSelect(KpiNormal kpi){
		currentKpi = kpi;
	}
	public void onSourceSelect(KpiDataSource ds){
		currentDataSource = ds;
	}
	public void saveDsReliabilityParam(KpiDataSource ds){
		dao.update(ds, KpiDataSource.class);
		//计算数据源关联的所有kpi的可靠度
		km.updateDsParentsKpiReliability(ds.getId());
		//重置整个树的值
		init();
	}
	public void saveKpiWeight(KpiWeight w){
		w = dao.update(w, KpiWeight.class);
		//验证w和是否超过1
		if(km.validationKpiWeightByKpi(w.getPid())>1){
			w.setValue(0d);
			w = dao.update(w, KpiWeight.class);
			addErrorMessage("权重之和不可超过1！");
		}
		//更新与weight相关的父kpi们的值
		km.updateSelfAndParentsKpiReliability(w.getPid());
		//重置整个树
		init();
	}
	private void loadChildren(TreeNode node,String nodeType){
		List<KpiGroup> groups = new ArrayList<>();
		if(node.getData().getClass().equals(String.class)){
			groups = groupGroupMap.get("root");
		}else{
			groups = groupGroupMap.get(((KpiGroup)node.getData()).getId());
		}
		for(KpiGroup g:groups){
			String id = g.getId();
			boolean hasGroup = groupGroupMap.containsKey(id);
			boolean hasKpi = groupKpiMap.containsKey(id);
			if(!hasGroup && !hasKpi){
				new DefaultTreeNode(nodeType,g,node);
				continue;
			}
			TreeNode group = new LibTreeNode(nodeType,g,node);
			if(hasGroup){
				loadChildren(group,"childGroup");
			}
			if(hasKpi){
				loadGroupChildren(group);
			}
		}
		node.setExpanded(true);
	}
	private void loadGroupChildren(TreeNode node){
		String groupid = ((KpiGroup)node.getData()).getId();
		Map<String,TreeNode> levelNodeMap = new HashMap<>();
		List<TreeNode> levelNodeList = new ArrayList<>();
		//group下面的level节点需要按照value排序
		for(KpiLevel lev : levels){
			TreeNode level = new LibTreeNode("level",lev,node);
			levelNodeMap.put(lev.getId(), level);
			levelNodeList.add(level);
			level.setExpanded(true);
		}
		
		for(KpiNormal n:groupKpiMap.get(groupid)){
			String levelid = n.getKpiLevel();
			TreeNode pnode = node;
			int levelvalue = 0;
			//如果有level，那就建立level节点
			if(levelid != null){
				KpiLevel kpilevel = levelsmap.get(levelid);
				levelvalue = kpilevel.getValue();
				pnode = levelNodeMap.get(levelid);
				levelNodeList.remove(pnode);
			}
			createKpiNode(pnode,levelvalue,n);
		}
		//去掉group里没有的level节点
		node.getChildren().removeAll(levelNodeList);
		node.setExpanded(true);
	}
	//建kpi节点。若kpi没有子，则建立DefaultTreeNode。若有，则根据可靠度建立
	private void createKpiNode(TreeNode node,int levelvalue,KpiNormal n){
		TreeNode kpi = null;
		if(kpiWeightsMap.containsKey(n.getId())){
			if(n.getReliabilityValue() >= levelvalue){
				kpi = new LibTreeNode("kpiCorrect", n, node);
			}else{
				kpi = new LibTreeNode("kpiError", n, node);
			}
			loadKpiChildren(kpi);
		}else{
			new DefaultTreeNode("kpiCorrect", n, node);
		}
	}
	private void loadKpiChildren(TreeNode node){
		KpiNormal kpi = null;
		if(node.getData().getClass().toString().equals(KpiNormal.class.toString())){
			kpi = (KpiNormal)node.getData();
		}else{
			kpi = (KpiNormal) ((KpiWeightComplete)node.getData()).getChild();
		}
		String id = kpi.getId();
		List<KpiWeight> ws = kpiWeightsMap.get(id);
		for(KpiWeight w : ws){
			KpiWeightComplete kw = new KpiWeightComplete(w,kpi);
			int levelvalue = 0;
			if(w.getCtype().equals("kpinormal")){
				KpiNormal ckpi = kpismap.get(w.getCid());
				kw.setChild(ckpi);
				if(ckpi.getKpiLevel() != null){
					KpiLevel l = levelsmap.get(ckpi.getId());
					if(l != null){
						levelvalue = l.getValue();
					}
				}
			}else if(w.getCtype().equals("kpidatasource")){
				kw.setChild(dsmap.get(w.getCid()));
			}
			createKpiWeightNode(node,levelvalue,kw);
		}
		node.setExpanded(true);
	}
	private void createKpiWeightNode(TreeNode node,int levelvalue,KpiWeightComplete kw){
		TreeNode weight = null;
		String type = kw.getKpiweight().getCtype();
		if(type.equals("kpinormal")){
			if( kpiWeightsMap.containsKey(kw.getKpiweight().getCid())){
				if(kw.getKpiweight().getValue() >= levelvalue){
					weight = new LibTreeNode("kpiWeightCorrect", kw, node);
				}else{
					weight = new LibTreeNode("kpiWeightError", kw, node);
				}
				loadKpiChildren(weight);
			}else{
				new DefaultTreeNode("kpiWeightCorrect", kw, node);
			}
		}else if(type.equals("kpidatasource")){
			KpiDataSource ds = (KpiDataSource) kw.getChild();
			if(ds.isAvailable() && ds.getReliabilityParam() >0){
				new DefaultTreeNode("dsWeightCorrect", kw, node);
			}else{
				new DefaultTreeNode("dsWeightError", kw, node);
			}
		}
	}
	public TreeNode getRoot() {
		return root;
	}
	public void setRoot(TreeNode root) {
		this.root = root;
	}
	public TreeNode getSelectedNode() {
		return selectedNode;
	}
	public void setSelectedNode(TreeNode selectedNode) {
		this.selectedNode = selectedNode;
	}
	public KpiNormal getCurrentKpi() {
		return currentKpi;
	}
	public void setCurrentKpi(KpiNormal currentKpi) {
		this.currentKpi = currentKpi;
	}
	public KpiDataSource getCurrentDataSource() {
		return currentDataSource;
	}
	public void setCurrentDataSource(KpiDataSource currentDataSource) {
		this.currentDataSource = currentDataSource;
	}
	public boolean isRealiIsShow() {
		return realiIsShow;
	}
	public void setRealiIsShow(boolean realiIsShow) {
		this.realiIsShow = realiIsShow;
	}
	public List<KpiLevel> getLevels() {
		return levels;
	}
	public void setLevels(List<KpiLevel> levels) {
		this.levels = levels;
	}
	
}